package com.sxkiler.demo.web.config;//package com.sxkiler.demo.configuration;

import cn.hutool.core.util.StrUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

/**
 * @Author: wangsen
 * @Date: 2020/4/16 15:02
 * @Description:
 **/
@Aspect
public class DataSourceAspect implements Ordered {
    private final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);

    @Pointcut("execution(* com.sxkiler.demo.*.service.impl.*.*(..))")
    public void serviceAspect() {
    }

    @Before("serviceAspect()")
    public void before(JoinPoint point) {
        try {
            Method m = ((MethodSignature) point.getSignature()).getMethod();
            boolean isMarker = false;
            if (m != null && m.isAnnotationPresent(DataSourceMarker.class)) {
                DataSourceMarker annotation = m.getAnnotation(DataSourceMarker.class);
                if (StrUtil.isNotEmpty(annotation.datasourceName())) {
                    isMarker = true;
                    DynamicDataSourceHolder.putDataSource(annotation.datasourceName());
                }
            }
            if(!isMarker) {
                if (m != null && m.isAnnotationPresent(Transactional.class)) {
                    Transactional annotation = m.getAnnotation(Transactional.class);
                    if (annotation.readOnly()) {
//                        logger.debug("put_data_source,{},{}", m.getName(), DynamicDataSourceHolder.DATA_SOURCE_READ);
                        DynamicDataSourceHolder.putDataSource(DynamicDataSourceHolder.DATA_SOURCE_READ);
                    } else {
//                        logger.debug("put_data_source,{},{}", m.getName(), DynamicDataSourceHolder.DATA_SOURCE_WRITE);
                        DynamicDataSourceHolder.putDataSource(DynamicDataSourceHolder.DATA_SOURCE_WRITE);
                    }
                } else if (guessIsReadMethod(m)) {
//                    logger.debug("put_data_source,{},{}", m.getName(), DynamicDataSourceHolder.DATA_SOURCE_READ);
                    DynamicDataSourceHolder.putDataSource(DynamicDataSourceHolder.DATA_SOURCE_READ);
                } else {
//                    logger.debug("put_data_source,{},{}", m.getName(), DynamicDataSourceHolder.DATA_SOURCE_WRITE);
                    DynamicDataSourceHolder.putDataSource(DynamicDataSourceHolder.DATA_SOURCE_WRITE);
                }
            }
        }catch (Exception e) {
            logger.error("set dynamic datasource arise error"+e.getMessage(), e);
        }
    }
    /**
     * 推测是否是只读方法，以方法名的第一个单词推测是，目前包含范围有：get, select, query, find, export, fetch, is, page, search, count
     * @author fuqiang_wen 2018/7/26
     * @param method
     * @return
     */
    private boolean guessIsReadMethod(Method method) {
        String methodName = method.getName();
        return methodName.startsWith("get") || methodName.startsWith("select") || methodName.startsWith("query")
                || methodName.startsWith("find") || methodName.startsWith("export") || methodName.startsWith("fetch")
                || methodName.startsWith("is") || methodName.startsWith("page") || methodName.startsWith("search")
                || methodName.startsWith("count");
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
